package com.zzy.mccjt.gateway.common.filter.privacy;

import com.zzy.mccjt.gateway.common.properties.PrivacyHandleProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

/**
 * @author likejie
 * @version 1.0
 * @description: 隐私数据处理
 * @date 2019/8/28 20:00
 */
@Slf4j
public abstract class AbstractPrivacyHandle {

   /* @Autowired
    private PrivacyHandleProperties privacyHandleProperties;
    *//**
     * 获取处理过的数据
     * @param path  请求接口的URL
     * @param originContent  原始body 数据
     *//*
    public String getData(String path, String originContent, PrivacyHandleProperties.HandleTarget target) {
        log.info("privacyHandle -> path:{}",path);
        JSONObject root = JSONObject.parseObject(originContent);
        if (root == null) {
            return originContent;
        }
        JSONObject res = new JSONObject(root);
        return getHandleResult(res, target);
    }
    *//**
     * 检查是否需要加/解密处理
     *//*
    public PrivacyHandleProperties.HandleTarget checkIsHandle(String path) {

        HashMap<String, PrivacyHandleProperties.HandleTarget> targets = privacyHandleProperties.getUrlMap();
        List<PrivacyHandleProperties.HandleTarget> pers = privacyHandleProperties.getPers();
        //url 匹配
        int handleUrlSize= Optional.ofNullable(targets).map(HashMap::size).orElse(0);
        //前缀匹配
        int persSize= Optional.ofNullable(pers).map(List::size).orElse(0);
        if (handleUrlSize==0&&persSize==0) {
            log.debug("-------->未配置,不进行数据加密处理");
            return null;
        }
        String uri = path.replaceAll("//", "/");
        return needFilter(targets, pers, uri);
    }
    *//**
     * 检查是否需要加/解密处理
     *//*
    private String getHandleResult(JSONObject root, PrivacyHandleProperties.HandleTarget target){
        JSONObject res = new JSONObject(root);
        //层阶遍历数据
        LinkedList<JSONObject> queue = new LinkedList<>();
        queue.offer(res);
        if (privacyHandleProperties.isAnalysisModel()) {
            bfsByCoefficient(target, root, res, queue);
        } else {
            bfsByDeep(target, root, res, queue);
        }
        return JSONObject.toJSONString(res);
    }

    *//***
     * 解析 深度控制
     * @param
     * @param target
     * @param root
     * @param res
     * @param queue
     *//*
    private void bfsByDeep(PrivacyHandleProperties.HandleTarget target,
                           JSONObject root,
                           JSONObject res,
                           LinkedList<JSONObject> queue) {
        log.debug("-------->深度控制");
        int currentDeep = 1;
        int maxDeep = privacyHandleProperties.getDeep();
        LinkedList<JSONObject> floor = new LinkedList<>();
        HashMap<String, String> params;
        JSONObject add;
        while (true) {
            if (currentDeep > maxDeep) {
                log.debug("-------->超出深度:" + JSON.toJSONString(res, SerializerFeature.WriteMapNullValue) + "目前深度：" + privacyHandleProperties.getDeep());
                break;
            }
            boolean isClear = true;
            for (JSONObject jsonObject : queue) {
                params = new HashMap<>();
                add = new JSONObject();
                LinkedList<JSONObject> inside = parse(jsonObject, params, target);
                //加解密处理
                if (null != params && params.size() > 0) {
                    handle(add, params);
                }
                //追加
                jsonObject.putAll(add);
                //在第一次进入for循环时进行清空
                if (isClear) {
                    floor.clear();
                    isClear = false;
                }
                floor.addAll(inside);
            }
            queue = new LinkedList<>(floor);
            if (queue.isEmpty()) {
                break;
            }
            currentDeep++;
        }
    }

    *//***
     * 解析 复杂度控制
     * @param
     * @param target
     * @param root
     * @param res
     * @param queue
     *//*
    private void bfsByCoefficient(PrivacyHandleProperties.HandleTarget target, JSONObject root, JSONObject res, LinkedList<JSONObject> queue) {
        log.debug("-------->复杂度控制");
        //解析复杂度系数
        int coefficient = 1;
        int maxCoefficient = privacyHandleProperties.getCoefficient();
        while (true) {
            JSONObject jo = queue.poll();
            //表示遍历完成
            if (null == jo) {
                break;
            }
            if (coefficient >= maxCoefficient) {
                //超出解析复杂度 不再加解密 可能不是内部对象
                log.debug("-------->超出复杂度:" + JSON.toJSONString(res, SerializerFeature.WriteMapNullValue) + "目前复杂度：" + privacyHandleProperties.getDeep());
                break;
            }
            JSONObject joAdd = new JSONObject();
            HashMap<String, String> params = new HashMap<>(jo.keySet().size());
            for (String key : jo.keySet()) {
                Object o = jo.get(key);
                if (null != o) {
                    //目前fastjson的数据对象 JSON继承树下只有JSONObject和JSONArray 以后如果有新数据类型 需要同步更新此处
                    if (o instanceof JSONObject) {
                        queue.offer((JSONObject) o);
                        coefficient++;
                    } else if (o instanceof JSONArray) {
                        JSONArray ja = (JSONArray) o;
                        for (int i = 0; i < ja.size(); i++) {
                            if (!(ja.get(i) instanceof JSONObject)) {
                                //不处理
                                continue;
                            }
                            queue.offer(ja.getJSONObject(i));
                        }
                        coefficient++;
                    } else {
                        //非JSON树下对象 将需要加解密的key 放入params
                        paramReady(params, target, key, o, jo);
                    }
                }
            }
            if (null != params && params.size() > 0) {
                handle(joAdd, params);
            }
            //追加
            jo.putAll(joAdd);
        }
    }


    private LinkedList<JSONObject> parse(JSONObject origin, HashMap<String, String> params, PrivacyHandleProperties.HandleTarget target) {
        LinkedList<JSONObject> result = new LinkedList<>();
        for (String key : origin.keySet()) {
            Object o = origin.get(key);
            if (null != o) {
                //目前fastjson的数据对象 JSON继承树下只有JSONObject和JSONArray 以后如果有新数据类型 需要同步更新此处
                if (o instanceof JSONObject) {
                    result.offer((JSONObject) o);
                } else if (o instanceof JSONArray) {
                    JSONArray ja = (JSONArray) o;
                    for (int i = 0; i < ja.size(); i++) {
                        if (!(ja.get(i) instanceof JSONObject)) {
                            //不处理
                            continue;
                        }
                        result.offer(ja.getJSONObject(i));
                    }
                } else {
                    //非JSON树下对象 将需要加解密的key 放入params
                    paramReady(params, target, key, o, origin);
                }
            }
        }
        return result;
    }

    *//**
     * 功能描述: 是否需要过滤
     *
     * @auther: liuhongliang
     * @date: 2018/12/6 15:12
     *//*
    public abstract PrivacyHandleProperties.HandleTarget needFilter(HashMap<String, PrivacyHandleProperties.HandleTarget> targets, List<PrivacyHandleProperties.HandleTarget> pers, String uri);


    *//**
     * 功能描述: 加解密参数准备
     * params 待准备的加解密参数
     * target 该接口配置
     * key 当前待处理的属性
     * o 当前待处理属性的值
     * jo 当前层级对象
     *
     * @auther: liuhongliang
     * @date: 2018/12/6 15:03
     *//*
    public abstract HashMap<String, String> paramReady(HashMap<String, String> params, PrivacyHandleProperties.HandleTarget target, String key, Object o, JSONObject jo) ;

    *//**
     * 功能描述: 加解密处理
     * joAdd 待追加属性容器
     * params 加解密参数
     *
     * @auther: liuhongliang
     * @date: 2018/12/6 15:03
     *//*
    public abstract void handle(JSONObject joAdd, HashMap<String, String> params);*/
}
